# Copyright (C) 2007 Richard Boulton
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
r"""fetcher.py: Feed fetching and updating.

"""

import threading

class Fetcher(threading.Thread):
    """Class which manages fetching the feeds.

    """
    def __init__(self, store):
        threading.Thread.__init__(self)
        self.store = store
        self.stop_requested = False
        self.condition = threading.Condition()

    def inform_of_change(self):
        """Inform the fetcher of a change to the list of feeds to fetch.

        The fetcher will recalculate the time at which it next needs to perform
        an update, if it is currently waiting for a scheduled update.

        """
        self.condition.acquire()
        try:
            self.condition.notifyAll()
        finally:
            self.condition.release()

    def wait_for_update(self):
        """Wait until the next update, or the condition is signalled.

        """
        self.condition.acquire()
        try:
            update_wait = self.store.get_seconds_until_next_update()
            if update_wait is None:
                self.condition.wait()
            if update_wait <= 0:
                return
            self.condition.wait(update_wait)
        finally:
            self.condition.release()

    def perform_update(self):
        """Perform the next scheduled update.

        """
        FIXME

    def stop(self):
        """Stop the fetching loop.

        Any fetches currently in progress will first be finished, or aborted.

        """
        self.condition.acquire()
        try:
            self.stop_requested = True
            self.condition.notifyAll()
        finally:
            self.condition.release()

    def run(self):
        """Start the fetching loop.

        The loop will continue until the "stop()" method is called (presumably,
        by another thread).

        """
        self.condition.acquire()
        try:
            while not self.stop_requested:
                self.wait_for_update()
                if self.stop_requested:
                    break
                self.condition.release()
                try:
                    self.perform_update()
                finally:
                    self.condition.acquire()
        finally:
            self.condition.release()

